/*
  This file is part of bnc.

  bnc is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  bnc is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with bnc.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
  gcc bnc-gtk.c manager-gtk.c -o bnc-gtk `pkg-config --cflags --libs gtk+-2.0`
*/

/*
  Dependencies: libglib2.0
                libgtk2.0
                libpango1.0
                libglib2.0-dev
                libgtk2.0-dev
                libpango1.0-dev
*/

#include <unistd.h>
#include <gtk/gtk.h>
#include "./manager-gtk.h"

#define PATH "/usr/share/pixmaps/bnc.png"
#define BUFFERSIZE 16777216

const char cTemplate[]="bnc-XXXXXX";
const char cTemporaryDirectory[]="/tmp/";
const char cCmdC[]="/usr/bin/bnc c ";
const char cCmdX[]="/usr/bin/bnc x ";
const char cFileI[]="/insert.bnc";
const char cFileM[]="/merge.bnc";
const char cFileR[]="/remove.bnc";

/*
  fileE is used to create a list of files to be extracted by back-end bnc.
*/
gboolean fileE (GtkTreeModel* aModel,
                GtkTreePath* aPath,
                GtkTreeIter* aIter,
                gpointer aList)
{
  GtkWidget* lDialog;
  GtkWidget* lPassword;
  GtkWidget* lCheckButton;
  int lRun;
  char* lPwd;
  char* lFileName;
  char* lFileNameQuoted;
  char* lEncryption;
  char* lCmd;
  char* lPwds;
  int* lAll=(int*)g_list_nth_data(aList, 5);

  lCmd=(char*)g_list_nth_data(aList, 3);
  lPwds=(char*)g_list_nth_data(aList, 4);

/*
  Getting FileName and Encryption option from a row of selected items.
*/

  if (gtk_tree_model_get_iter(aModel, aIter, aPath))
  {
    gtk_tree_model_get(aModel,
                       aIter,
                       0,
                       &lFileName,
                       -1);
    gtk_tree_model_get(aModel,
                       aIter,
                       3,
                       &lEncryption,
                       -1);
  }

  /*
    If the file is encrypted and we have not set a password for it to be
    extracted. Do so by dialog.
  */

  if (*lAll==0 && lEncryption[0]=='Y')
  {
    lDialog=gtk_dialog_new_with_buttons(lFileName,
                                        g_list_nth_data(aList, 0),
                                        GTK_DIALOG_MODAL |
                                        GTK_DIALOG_DESTROY_WITH_PARENT |
                                        GTK_DIALOG_NO_SEPARATOR,
                                        GTK_STOCK_OK,
                                        GTK_RESPONSE_ACCEPT,
                                        GTK_STOCK_CANCEL,
                                        GTK_RESPONSE_REJECT,
                                        NULL);

    lPassword=gtk_entry_new();

      gtk_entry_set_visibility(GTK_ENTRY(lPassword), FALSE);

    gtk_container_add(
      GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
      lPassword);

    lCheckButton=gtk_check_button_new_with_mnemonic("Apply for _All");

    gtk_container_add(
      GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
      lCheckButton);

    gtk_widget_show_all(lDialog);

    lRun=gtk_dialog_run(GTK_DIALOG(lDialog));

    switch(lRun)
    {
      /*
        Get password from dialog.
	Quote the filename to override splitting it into pieces.
      */
      case GTK_RESPONSE_ACCEPT:
        lPwd=(char*)gtk_entry_get_text(GTK_ENTRY(lPassword));

        lFileNameQuoted=(char*)malloc(strlen(lFileName)+3);
        lFileNameQuoted[0]='"';
        memcpy(lFileNameQuoted+1, lFileName, strlen(lFileName));
        memcpy(lFileNameQuoted+strlen(lFileName)+1, "\"", 2);

        memcpy(lCmd+strlen(lCmd), lFileNameQuoted, strlen(lFileNameQuoted)+1);
        memcpy(lCmd+strlen(lCmd), " ", 2);

        memcpy(lPwds+strlen(lPwds), lPwd, strlen(lPwd)+1);
        memcpy(lPwds+strlen(lPwds), "\n", 2);

        free(lFileNameQuoted);

        /*
	  Toggle the password for all files to come.
	*/
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lCheckButton)))
        {
          *lAll=1;

          memcpy(lPwds+strlen(lPwds), "A\n", 3);
        } else {
          memcpy(lPwds+strlen(lPwds), "n\n", 3);
        }

        break;
      case GTK_RESPONSE_CANCEL:
        break;
    }

    gtk_widget_destroy(lDialog);
  } else {
    /*
      If the file was not encrypted hand in only the quoted filename.
    */
    lFileNameQuoted=(char*)malloc(strlen(lFileName)+3);
    lFileNameQuoted[0]='"';
    memcpy(lFileNameQuoted+1, lFileName, strlen(lFileName));
    memcpy(lFileNameQuoted+strlen(lFileName)+1, "\"", 2);

    memcpy(lCmd+strlen(lCmd), lFileNameQuoted, strlen(lFileNameQuoted)+1);
    memcpy(lCmd+strlen(lCmd), " ", 2);
  }

  g_free(lFileName);
  g_free(lEncryption);

  return TRUE;
}

/*
  extractDialog brings up a dialog for every single file selected.
*/
int static extractDialog (GList* aList)
{
  GtkTreeView* lTree;
  GtkTreeSelection* lSelection;
  int lAll;
  char* lCmd;
  char* lPwds;
  char* lFileName;
  FILE* lPipe;
  char* lArch;
  int lCmdMinLen;
  int i, j;
  double lSize, lTotal;

  lTree=g_list_nth_data(aList, 1);
  lSelection=gtk_tree_view_get_selection(lTree);

  lAll=0;

  /*
    Prepare space for the command with the list of files and corresponding
    passwords.
  */
  lCmd=(char*)malloc(4096);
  lPwds=(char*)malloc(4096);

  lFileName=(char*)malloc(512);

  lArch=(char*)gtk_label_get_text(g_list_nth_data(aList, 2));

  memcpy(lCmd, cCmdX, 16);

  /*
    Insert the command call.
  */
  memcpy(lCmd+15, lArch, strlen(lArch)+1);
  lCmdMinLen=strlen(lCmd);
  lCmd[lCmdMinLen+1]=0;
  lCmd[lCmdMinLen]=' ';
  lCmdMinLen++;

  lPwds[0]=0;

  /*
    Prepare to call fileE individualy for every file from selection.
  */
  aList=g_list_append(aList, lCmd);
  aList=g_list_append(aList, lPwds);
  aList=g_list_append(aList, &lAll);

  /*
    Call fileE for all files.
  */
  gtk_tree_selection_selected_foreach(lSelection,
                                      (GtkTreeSelectionForeachFunc)fileE,
                                      aList);

  /*
    Call the back-end bnc to extract files.
  */
  if (strlen(lCmd)>lCmdMinLen) //Empty list of files means
                               //EVERYTHING HAS BEEN CANCLED >>
                               //NOTHING SHOULD BE EXTRACTED
  {
    lPipe=popen(lCmd, "w");
    fwrite(lPwds, 1, strlen(lPwds), lPipe);
    pclose(lPipe);
  }

  /*
    Free the memory.
  */
  free(lCmd);
  free(lPwds);

  free(lFileName);

  aList=g_list_remove(aList, lCmd);
  aList=g_list_remove(aList, lPwds);
  aList=g_list_remove(aList, &lAll);

  return 0;
}

/*
  fileO is used to open given file of bnc type.
*/
int static fileO (GList* aList, char* aFileName)
{
  GtkListStore* lStore;
  GtkLabel* lLabel;
  GtkTreeIter lIter;
  char*** lTable;
  char* lCmd;
  int i, j;
  FILE* lFile;
  manager* lManager;

  lManager=g_list_nth_data(aList, 3);

  /*
    Check for the file. If it doesnt exist. We may create a new one.
  */
  lFile=fopen(aFileName, "r");
  if (lFile==NULL)
  {
    lCmd=(char*)malloc(256*sizeof(char));
    memcpy(lCmd, cCmdC, strlen(cCmdC)+1);
    memcpy(lCmd+strlen(lCmd), aFileName, strlen(aFileName)+1);

    system(lCmd);

    free(lCmd);

    lFile=fopen(aFileName, "r");
    if (lFile==NULL)  
      return 1;
  }
  fclose(lFile);

  lLabel=g_list_nth_data(aList, 1);
  lStore=g_list_nth_data(aList, 2);

  i=strlen(aFileName)-1;

  /*
    Get the path to the file and the filename itself without the path.
  */
  while (i+1>0 && aFileName[i]!='/') i--;

  if (aFileName[i]=='/') aFileName[i]=0;
  if (i>0) chdir(aFileName); // Switch to the directory.

  /*
    Change the name displayed by bnc-gtk.
  */
  if (gtk_label_get_text(lLabel)!=aFileName)
    gtk_label_set_text(lLabel, aFileName+i+1);

  /*
    Open the bnc archive and get the list of its content.
  */
  managerOpenBnc(lManager, aFileName+i+1);
  lTable=managerListFiles(lManager);

  gtk_list_store_clear(lStore);

  /*
    Put the contetnt into table displayed by bnc-gtk.
  */
  for (i=0; lTable[i]!=0; i++)
  {
    gtk_list_store_append(lStore, &lIter);
    gtk_list_store_set(lStore, &lIter,
                       0, lTable[i][0],
                       1, lTable[i][1],
                       2, lTable[i][2],
                       3, lTable[i][3],
                       -1);
  }
  return 0;
}

/*
  openDialog is used to bring up a dialog to select archive file to be opened.
*/
static int openDialog (GList* aList,
                       GdkEvent* aEvent,
		       gpointer aData)
{
  int lRun;
  GtkWidget* lFile;

  /*
    Prepare the dialog.
  */
  lFile=gtk_file_chooser_dialog_new("Open",
                                     GTK_WINDOW(g_list_nth_data(aList, 0)),
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
                                     GTK_STOCK_CANCEL,
                                     GTK_RESPONSE_CANCEL,
                                     GTK_STOCK_OPEN,
                                     GTK_RESPONSE_ACCEPT,
                                     NULL);

  gtk_widget_show_all(lFile);

  lRun=gtk_dialog_run(GTK_DIALOG(lFile));

  switch(lRun)
  {
    case GTK_RESPONSE_ACCEPT:
      /*
        Open the selected file.
      */
      fileO(aList,
	    gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(lFile)));
      break;
    case GTK_RESPONSE_CANCEL:
      break;
  }

  gtk_widget_destroy(lFile);

  return TRUE;
}

/*
  fileI is used to insert files into the archive.
*/
int static fileI (GList* aList, GSList* aFileNames)
{
  char* lCmd;
  char* lPwd;
  char* lPwds;
  char* lTemp;
  char* lFileName1;
  char* lFileName2;
  int i, j;
  manager* lManager1;
  manager* lManager2;
  GtkWidget* lDialog;
  GtkWidget* lPassword;
  GtkWidget* lCheckButtonE;
  GtkWidget* lCheckButtonC;
  GtkWidget* lCheckButton;
  int lAll=0;
  int lRun;
  int lCmdMinLen;
  FILE* lPipe;
  FILE* lFileIn;
  FILE* lFileOut;
  char* lBuffer;
  unsigned int lLength;

  /*
    Prepare managers for two bnc archives.
  */
  lManager1=g_list_nth_data(aList, 3);
  lManager2=(manager*)malloc(sizeof(manager));
  managerConstructor(lManager2);
  lTemp=g_list_nth_data(aList, 5);

  /*
    Prepare space for command call, list of passwords and filenames.
  */
  lCmd=(char*)malloc(1024*sizeof(char));
  lPwds=(char*)malloc(1024*sizeof(char));
  lFileName1=(char*)malloc(256*sizeof(char));
  lFileName2=(char*)malloc(256*sizeof(char));

  lPwds[0]=0;

  /*
    Prepare the call.
  */
  memcpy(lCmd, cCmdC, strlen(cCmdC)+1);
  memcpy(lCmd+strlen(lCmd), lTemp, strlen(lTemp)+1);
  memcpy(lCmd+strlen(lCmd), cFileI, strlen(cFileI)+1);

  lCmdMinLen=strlen(lCmd);

  /*
    For every file bring up a dialog to ask the user what to do with that file.
  */
  for (i=0; g_slist_nth_data(aFileNames, i)!=NULL; i++)
  {
    if (lAll==0)
    {
      lDialog=gtk_dialog_new_with_buttons(g_slist_nth_data(aFileNames, i),
                                          g_list_nth_data(aList, 0),
                                          GTK_DIALOG_MODAL |
                                          GTK_DIALOG_DESTROY_WITH_PARENT |
                                          GTK_DIALOG_NO_SEPARATOR,
                                          GTK_STOCK_OK,
                                          GTK_RESPONSE_ACCEPT,
                                          NULL);

      lPassword=gtk_entry_new();

        gtk_entry_set_visibility(GTK_ENTRY(lPassword), FALSE);

      gtk_container_add(
        GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
        lPassword);

      lCheckButtonE=gtk_check_button_new_with_mnemonic("_Ecrypt");
      lCheckButtonC=gtk_check_button_new_with_mnemonic("_Compress");
      lCheckButton=gtk_check_button_new_with_mnemonic("Apply for _All");

      gtk_container_add(
        GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
        lCheckButtonC);
      gtk_container_add(
        GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
        lCheckButtonE);
      gtk_container_add(
        GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(lDialog))),
        lCheckButton);

      gtk_widget_show_all(lDialog);

      lRun=gtk_dialog_run(GTK_DIALOG(lDialog));

      memcpy(lCmd+strlen(lCmd), " -n", 4);

      switch(lRun)
      {
        case GTK_RESPONSE_ACCEPT:
	  /*
	    If the file is to be encrypted put the password to the list and put
	    the appropriate option to the command call.
	  */
	  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lCheckButtonE)))
	  {
	    lPwd=(char*)gtk_entry_get_text(GTK_ENTRY(lPassword));
            memcpy(lCmd+strlen(lCmd), " -e", 4);
	    if (lPwds[0]!=0) memcpy(lPwds, " ", 2);
	    memcpy(lPwds+strlen(lPwds),
	           lPwd,
	           strlen(lPwd)+1);
	    memcpy(lPwds+strlen(lPwds),
	           "\n",
		   2);
	  }

          /*
	    If the file is to be compressed put the appropriate option to the
	    command call.
	  */
	  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lCheckButtonC)))
	  {
            memcpy(lCmd+strlen(lCmd), " -c", 4);
	  }

          /*
	    If the user wishes to use these settings from now on do so.
	  */
	  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lCheckButton)))
	  {
	    lAll=1;
	    if (lPwds[0]!=0) memcpy(lPwds+strlen(lPwds), "A\n", 3);
	  }

          break;
      }

      gtk_widget_destroy(lDialog);
    }

    /*
      Add quoted file name right after the options.
    */
    memcpy(lCmd+strlen(lCmd), " ", 2);
    memcpy(lFileName1+1,
           g_slist_nth_data(aFileNames, i),
	   strlen(g_slist_nth_data(aFileNames, i))+1);
    lFileName1[0]='"';
    lFileName1[strlen(lFileName1)+1]=0;
    lFileName1[strlen(lFileName1)]='"';
    memcpy(lCmd+strlen(lCmd),
           lFileName1,
	   strlen(lFileName1)+1);
  }

  /*
    Call the back-end bnc.
  */
  if (strlen(lCmd)>lCmdMinLen) //Empty list of files means
                               //EVERYTHING HAS BEEN CANCLED >>
                               //NOTHING SHOULD BE EXTRACTED
  {
    lPipe=popen(lCmd, "w");
    fwrite(lPwds, 1, strlen(lPwds), lPipe);
    pclose(lPipe);
  }

  free(lCmd);
  free(lPwds);

  /*
    Open the newly created bnc archive of files to be inserted.
  */
  memcpy(lFileName1, lTemp, strlen(lTemp)+1);
  memcpy(lFileName1+strlen(lFileName1), cFileI, strlen(cFileI)+1);

  managerOpenBnc(lManager2, lFileName1);

  /*
    Create the name of the temporary merge file.
  */
  memcpy(lFileName2, lTemp, strlen(lTemp)+1);
  memcpy(lFileName2+strlen(lFileName2), cFileM, strlen(cFileM)+1);

  /*
    Merge the original file with the newly inserted files in the second file.
  */
  managerMergeFiles(lManager1, lManager2, lFileName2);

  /*
    Remove temporary insert file.
  */
  remove(lFileName1);

//  managerDestructor(lManager2); //memory is already deallocated.
  free(lManager2);

  /*
    Transfer the content of temporary merge file into the original file to
    finish the process;
  */
  lFileIn=fopen(lFileName2, "r");
  lFileOut=fopen((char*)gtk_label_get_text(g_list_nth_data(aList, 1)), "w");

  lBuffer=(char*)malloc(BUFFERSIZE);

  while ((lLength=fread(lBuffer, 1, BUFFERSIZE, lFileIn))>0)
  {
    fwrite(lBuffer, 1, lLength, lFileOut);
  }

  free(lBuffer);

  fclose(lFileIn);
  fclose(lFileOut);

  remove(lFileName2);

  free(lFileName1);
  free(lFileName2);

  /*
    Open the newly overwritten file.
  */
  fileO(aList, (char*)gtk_label_get_text(g_list_nth_data(aList, 1)));

  return 0;
}

/*
  insertDialog is supposed to give the user chance to select files that he
  wishes to insert into the archive.
*/
static int insertDialog (GList* aList,
                       GdkEvent* aEvent,
		       gpointer aData)
{
  int lRun;
  GtkWidget* lFile;

  /*
    Prepare the dialog (multiple files can be selected)
  */
  lFile=gtk_file_chooser_dialog_new("Insert",
                                     GTK_WINDOW(g_list_nth_data(aList, 0)),
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
                                     GTK_STOCK_CANCEL,
                                     GTK_RESPONSE_CANCEL,
                                     GTK_STOCK_OPEN,
                                     GTK_RESPONSE_ACCEPT,
                                     NULL);

  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(lFile), TRUE);

  gtk_widget_show_all(lFile);

  lRun=gtk_dialog_run(GTK_DIALOG(lFile));

  switch(lRun)
  {
    case GTK_RESPONSE_ACCEPT:
      /*
        Insert these files into the archive.
      */
      fileI(aList,
	    gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(lFile)));
      break;
    case GTK_RESPONSE_CANCEL:
      break;
  }

  gtk_widget_destroy(lFile);

  return TRUE;
}

/*
  fileRList is supposed to put a filename into the list of files to be removed.
*/
gboolean fileRList (GtkTreeModel* aModel,
                    GtkTreePath* aPath,
                    GtkTreeIter* aIter,
                    gpointer aList)
{
  char* lFileName;
  char** lList=*(char***)g_list_nth_data(aList, 6);
  unsigned int i=0;

  while (lList[i]!=NULL)
    i++;

  /*
    Enlarge the list.
  */
  lList=(char**)realloc(lList, (i+2)*sizeof(char*));
  lList[i]=(char*)malloc(256);

  if (gtk_tree_model_get_iter(aModel, aIter, aPath))
  {
    gtk_tree_model_get(aModel,
                       aIter,
                       0,
                       &lFileName,
                       -1);
  }

  /*
    Add the file name into the list.
  */
  memcpy(lList[i], lFileName, strlen(lFileName)+1);
  lList[i+1]=NULL;

  *(char***)g_list_nth_data(aList, 6)=lList;

  g_free(lFileName);

  return TRUE;
}

/*
  fileR removes files from the archive.
*/
int static fileR (GList* aList)
{
  GtkTreeView* lTree;
  GtkTreeSelection* lSelection;
  char** lList;
  char* lFileName;
  int i;
  FILE* lFileIn;
  FILE* lFileOut;
  char* lBuffer;
  char* lTemp;
  unsigned int lLength;

  lList=(char**)malloc(sizeof(char*));
  lList[0]=NULL;

  lTree=g_list_nth_data(aList, 4);
  lSelection=gtk_tree_view_get_selection(lTree);
  lTemp=g_list_nth_data(aList, 5);

  aList=g_list_append(aList, &lList);

  /*
    Put all the selected files into a list.
  */
  gtk_tree_selection_selected_foreach(lSelection,
                                      (GtkTreeSelectionForeachFunc)fileRList,
                                      aList);

  lFileName=(char*)malloc((strlen(lTemp)+
                           strlen(cFileR)+1)*sizeof(char));
  memcpy(lFileName,
         lTemp,
	 strlen(lTemp));
  memcpy(lFileName+strlen(lTemp),
         cFileR,
	 strlen(cFileR)+1);

  /*
    Remove the files and save the result in the temporary directory.
  */
  managerRemoveFiles(g_list_nth_data(aList, 3),
                     lList,
		     lFileName);

  /*
    Last of all transfer the result into the original file.
  */
  lFileIn=fopen(lFileName, "r");
  lFileOut=fopen((char*)gtk_label_get_text(g_list_nth_data(aList, 1)), "w");

  lBuffer=(char*)malloc(BUFFERSIZE);

  while ((lLength=fread(lBuffer, 1, BUFFERSIZE, lFileIn))>0)
  {
    fwrite(lBuffer, 1, lLength, lFileOut);
  }

  free(lBuffer);

  fclose(lFileIn);
  fclose(lFileOut);

  /*
    Remove temporary file.
  */
  remove(lFileName);

  /*
    Open the newly rewritten file.
  */
  aList=g_list_remove(aList, lList);
  fileO(aList, (char*)gtk_label_get_text(g_list_nth_data(aList, 1)));

/*  while (lList[i]!=NULL)
    free(lList[i]);*/  // Already deallocated.
  free(lList);

  free(lFileName);

  return 0;
}

int main (int argc, char** argv)
{
  manager* lManager;

  lManager=(manager*)malloc(sizeof(manager));
  managerConstructor(lManager);

  /*
    Prepare temporary directory.
  */
  char lTemp[15];

    memcpy(lTemp, cTemporaryDirectory, 5);
    memcpy(lTemp+5, cTemplate, 11);

    mkdtemp(lTemp);

  GList* lList;

  GtkStatusIcon* lStatus;

  GtkWidget* lWindowMain;

    GtkWidget* lBoxW;

      GtkWidget* lBoxH;

        GtkWidget* lImage;
        GtkWidget* lLabel;

          char* lFileName;

      GtkWidget* lBoxM;

        GtkWidget* lScrollWindow;

          GtkWidget* lScroll;
          GtkWidget* lView;

            GtkCellRenderer* lRenderer;
            GtkListStore* lStore;
            GtkTreeSelection* lSelection;

        GtkWidget* lBoxR;

          GtkWidget* lButtonO;
          GtkWidget* lButtonI;
          GtkWidget* lButtonE;
          GtkWidget* lButtonX;
          GtkWidget* lButtonR;
          GtkWidget* lButtonQ;

      GtkWidget* lBoxF;

  gtk_init (&argc, &argv);

  /*
    Status Icon.
  */

  lStatus=gtk_status_icon_new_from_file(PATH);

  /*
    Main Window.
  */

  lWindowMain=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(lWindowMain, 480, 360);
    gtk_window_set_icon_from_file(GTK_WINDOW(lWindowMain), PATH, NULL);
    gtk_window_set_resizable(GTK_WINDOW(lWindowMain), FALSE);
    g_signal_connect(G_OBJECT(lWindowMain),
                     "delete_event",
                     G_CALLBACK(gtk_main_quit),
                     NULL);
    gtk_container_set_border_width(GTK_CONTAINER(lWindowMain), 10);

    /*
      Boxes, Image, List.
    */

    lBoxW=gtk_vbox_new(FALSE, 0);

    lBoxW=gtk_vbox_new(FALSE, 0);

      lBoxH=gtk_hbox_new(FALSE, 0);
      lBoxM=gtk_hbox_new(FALSE, 0);
      lBoxF=gtk_hbox_new(FALSE, 0);

        lImage=gtk_image_new_from_file(PATH);
        lLabel=gtk_label_new("No archive");

          lScrollWindow=gtk_scrolled_window_new(NULL, NULL);

            gtk_widget_set_size_request(lScrollWindow, 256, 192);

            lView=gtk_tree_view_new();
  
            lRenderer=gtk_cell_renderer_text_new();
              gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(lView),
                                                          -1,
                                                          "File",
                                                          lRenderer,
                                                          "text",
                                                          0,
                                                          NULL);
  
            lRenderer=gtk_cell_renderer_text_new();
              gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(lView),
                                                          -1,
                                                          "Size",
                                                          lRenderer,
                                                          "text",
                                                          1,
                                                          NULL);
  
            lRenderer=gtk_cell_renderer_text_new();
              gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(lView),
                                                          -1,
                                                          "Compressed",
                                                          lRenderer,
                                                          "text",
                                                          2,
                                                          NULL);
  
            lRenderer=gtk_cell_renderer_text_new();
              gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(lView),
                                                          -1,
                                                          "Encrypted",
                                                          lRenderer,
                                                          "text",
                                                          3,
                                                          NULL);
  
            lStore=gtk_list_store_new(4,
                                      G_TYPE_STRING,
                                      G_TYPE_STRING,
                                      G_TYPE_STRING,
                                      G_TYPE_STRING);
  
            gtk_tree_view_set_model(GTK_TREE_VIEW(lView),
                                    GTK_TREE_MODEL(lStore));
  
            g_object_unref(lStore);

            lSelection=gtk_tree_view_get_selection(GTK_TREE_VIEW(lView));
            gtk_tree_selection_set_mode(lSelection, GTK_SELECTION_MULTIPLE);

        lBoxR=gtk_vbox_new(FALSE, 0);

          /*
            List content.
          */

          lList=NULL;
          lList=g_list_append(lList, lWindowMain);
          lList=g_list_append(lList, lLabel);
          lList=g_list_append(lList, lStore);
	  lList=g_list_append(lList, lManager);

          if (argc>1) fileO(lList, argv[1]);

          /*
            Buttons.
          */

          lButtonO=gtk_button_new_with_mnemonic("_Open");
            g_signal_connect_swapped(lButtonO,
                                     "clicked",
                                     G_CALLBACK(openDialog),
                                     lList);

          /*
            List content.
          */

          lList=NULL;
          lList=g_list_append(lList, lWindowMain);
          lList=g_list_append(lList, lLabel);
          lList=g_list_append(lList, lStore);
	  lList=g_list_append(lList, lManager);
	  lList=g_list_append(lList, lView);
	  lList=g_list_append(lList, lTemp);

          lButtonI=gtk_button_new_with_mnemonic("_Insert");
            g_signal_connect_swapped(lButtonI,
                                     "clicked",
                                     G_CALLBACK(insertDialog),
                                     lList);

          /*
            List content.
          */

          lList=NULL;
          lList=g_list_append(lList, lWindowMain);
          lList=g_list_append(lList, lView);
          lList=g_list_append(lList, lLabel);

          lButtonE=gtk_button_new_with_mnemonic("_Extract");
            g_signal_connect_swapped(lButtonE,
                                     "clicked",
                                     G_CALLBACK(extractDialog),
                                     lList);
//          lButtonX=gtk_button_new_with_mnemonic("E_xecute");
          /*
            List content.
          */

          lList=NULL;
          lList=g_list_append(lList, lWindowMain);
          lList=g_list_append(lList, lLabel);
          lList=g_list_append(lList, lStore);
	  lList=g_list_append(lList, lManager);
	  lList=g_list_append(lList, lView);
	  lList=g_list_append(lList, lTemp);

          lButtonR=gtk_button_new_with_mnemonic("_Remove");
            g_signal_connect_swapped(lButtonR,
                                     "clicked",
                                     G_CALLBACK(fileR),
                                     lList);
          lButtonQ=gtk_button_new_with_mnemonic("_Quit");
            g_signal_connect_swapped(lButtonQ,
                                     "clicked",
                                     G_CALLBACK(gtk_main_quit),
                                     lWindowMain);

    /*
      Containment and packing.
    */

    gtk_container_add(GTK_CONTAINER(lWindowMain), lBoxW);

      gtk_box_pack_start(GTK_BOX(lBoxW), lBoxH, TRUE, TRUE, 0);
      gtk_box_pack_start(GTK_BOX(lBoxW), lBoxM, TRUE, TRUE, 0);
      gtk_box_pack_start(GTK_BOX(lBoxW), lBoxF, TRUE, TRUE, 0);

        gtk_box_pack_start(GTK_BOX(lBoxH), lImage, FALSE, FALSE, 0);
        gtk_box_pack_start(GTK_BOX(lBoxH), lLabel, FALSE, FALSE, 0);
  
        gtk_box_pack_start(GTK_BOX(lBoxM), lScrollWindow, TRUE, TRUE, 10);

          gtk_scrolled_window_add_with_viewport(
            GTK_SCROLLED_WINDOW(lScrollWindow),
            lView);

        gtk_box_pack_start(GTK_BOX(lBoxM), lBoxR, TRUE, TRUE, 0);

          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonO, FALSE, FALSE, 4);
          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonI, FALSE, FALSE, 4);
          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonE, FALSE, FALSE, 4);
//          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonX, FALSE, FALSE, 4);
          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonR, FALSE, FALSE, 4);
          gtk_box_pack_start(GTK_BOX(lBoxR), lButtonQ, FALSE, FALSE, 4);

    /*
      Show.
    */

    gtk_widget_show_all(lWindowMain);

  gtk_main();

  rmdir(lTemp);

  //managerDestructor(lManager); // Already deallocated.
  free(lManager);

  return 0;
}
